package contegor.scire.core.queries;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import contegor.scire.core.Concept;
import contegor.scire.core.Container;
import contegor.scire.core.Id;
import contegor.scire.core.IdFragment;
import contegor.scire.core.InfiniteSingletonList;
import contegor.scire.core.Link;
import contegor.scire.core.ReturnPoint;
import contegor.scire.core.Task;
import contegor.scire.core.TaskId;
import contegor.scire.core.Version;
import contegor.scire.core.WithConsequences;

/**
 * {@link Query} that returns the {@link Link} instances who's targets are the {@link Concept}s belonging to the target {@link Container}
 * with the {@link IdFragment}s given to the constructor. 
 *
 * @version $Revision: 1.2 $
 * @author  Héctor Cirbián Pousa ($Author: hector $)
 */
@Version("$Id: GetInputLinksFromIds.java,v 1.2 2010-02-01 10:55:41 hector Exp $")
public class GetLinksFromTargetIds extends Query<Link> implements WithConsequences<Link, Link>{
  private static final long serialVersionUID = 7848694791129181286L;

  private IdFragment[]                   ids;
  private List<GetLinksFromContainerAimingIds> consequences;

  public GetLinksFromTargetIds(Id targetContainerId, IdFragment ... ids) {
    super(targetContainerId);
    this.ids          = ids;
    this.consequences = null;
  }
  
  /** <b>Internal use only. </b>*/
  GetLinksFromTargetIds(TaskId taskId, Id targetContainerId, IdFragment ... ids) {
    super(taskId, targetContainerId);
    this.ids          = ids;
    this.consequences = null;
  }

  // TODO: We have to study if it is worth to put together the generated Queries.
  public void process(Container targetContainer) {
    TaskId subTaskId = this.taskId;
    for (IdFragment idf: ids) {
      Id        id    = new Id(this.targetContainerId, idf);
      Set<Link> links = targetContainer.getLinksReferring(id);
      if ((links != null) && (links.size() > 0))
        for (Link link: links)
          if (link.isVisibleTo(this.taskId.getTransactionId()))
            this.returnPoint.manage(this.taskId, link);
      Set<Id> externalContainersIds = targetContainer.getContainersReferring(idf);
      if (externalContainersIds != null) {
        if (this.consequences == null)
          this.consequences = new ArrayList<GetLinksFromContainerAimingIds>(externalContainersIds.size());
        for (Id exId: externalContainersIds) {
          this.consequences.add(new GetLinksFromContainerAimingIds(subTaskId = subTaskId.next(subTaskId == this.taskId), exId, id));
        }
      }
    }
  }

  @Override
  public List<? extends Task<Link>> getConsequences() {
    if (this.consequences == null)
      this.consequences = Collections.emptyList();
    return this.consequences;
  }

  @Override
  public List<? extends ReturnPoint<? super Link>> getConsequencesReturnPoints() {
    if (this.consequences == null)
      return Collections.emptyList();
    return new InfiniteSingletonList<ReturnPoint<? super Link>>(this.returnPoint, consequences.size());
  }
}
